// YemuScan
#include <stdarg.h>
#include "YemuEnv.h"

#define UART_TX_ADDR    (0x10000000)
#define UART_RX_ADDR    (0x10000004)

char GETCHAR() {
    return *((char*)UART_RX_ADDR);
}

void GETSTR(char* buf, int len) {
    int i = 0;
    char ch = 0;
    // skip leading space
    do {
        ch = GETCHAR();
    } while(ch == '\n');

    while(i < len - 1) {
        if(ch == '\n') break;
        buf[i++] = ch;
        ch = GETCHAR();
    }
    buf[i] = '\0';
}

unsigned long atoi(const char* str, int base) {
    int i = 0;
    unsigned long res = 0;
    if (!str[0]) {
        YemuPrint("empty input for atoi\n");
        YemuAssert(0);
    }
    while (str[i] != '\0') {
        unsigned char digit = 0;
        if (str[i] >= '0' && str[i] <= '9') digit = str[i] - '0';
        else if (str[i] >= 'A' && str[i] <= 'F') digit = str[i] - 'A' + 10;
        else if (str[i] >= 'a' && str[i] <= 'f') digit = str[i] - 'a' + 10;
        else {
            YemuPrint("illegal char '%c' in atoi\n", str[i]);
            YemuAssert(0);
        }
        if (digit >= base) {
            YemuPrint("digit '%c' out of base %d in atoi\n", str[i], base);
            YemuAssert(0);
        }
        res = res * base + digit;
        i++;
    }
    return res;
}

unsigned long GETUINT(int base) {
    char buf[32];
    GETSTR(buf, sizeof(buf));
    return atoi(buf, base);
}

long GETINT(int base) {
    char buf[32];
    GETSTR(buf, sizeof(buf));
    int neg = 0, i = 0;
    if (buf[0] == '-') {
        neg = 1;
        i = 1;
    }
    unsigned long res = atoi(buf + i, base);
    return neg ? -(long)res : (long)res;
}

void YemuScan(const char* fmt, ...) {
    va_list argptr;
    va_start(argptr, fmt);

    int i = 0;
    while (fmt[i]) {
        if (fmt[i] == '%') {
            i++;
            int longflag = 0;
            if (fmt[i] == 'l') { longflag = 1; i++; }
            switch(fmt[i]) {
                case 'c':
                    *va_arg(argptr, char*) = GETCHAR();
                    break;
                case 's': 
                    GETSTR(va_arg(argptr, char*), 256); // 调用者必须保证缓冲区足够大
                    break;
                case 'd':
                    if (longflag) *va_arg(argptr, long*) = GETINT(10);
                    else          *va_arg(argptr, int*) = (int)GETINT(10);
                    break;
                case 'u':
                    if (longflag) *va_arg(argptr, unsigned long*) = GETUINT(10);
                    else          *va_arg(argptr, unsigned int*) = (unsigned int)GETUINT(10);
                    break;
                case 'x':
                    if (longflag) *va_arg(argptr, unsigned long*) = GETUINT(16);
                    else          *va_arg(argptr, unsigned int*) = (unsigned int)GETUINT(16);
                    break;
                default:
                    YemuPrint("Unknown format in YemuScan: %%%c\n", fmt[i]);
                    YemuAssert(0);
            }
            i++;
        } else {
            i++; // skip other character
        }
    }
    va_end(argptr);
    return ;
    int condition = 0;
    
}